package com.ztsoft.user.config.shiro;

import com.ztsoft.user.config.jwt.JwtFilter;
import com.ztsoft.user.config.jwt.JwtSubjectFactory;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.mgt.SubjectFactory;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.mgt.DefaultWebSubjectFactory;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * shiro配置类
 *
 * @Author xwz
 * @Date 2022/8/30
 */
@Configuration
public class ShiroConfig {

    /**
     * 1、realm
     *
     * @return 自定义的realm
     */
    @Bean(name = "realm")
    public UserRealm getUserRealm() {
        return new UserRealm();
    }

    @Bean
    public DefaultWebSessionManager sessionManager() {
        DefaultWebSessionManager defaultSessionManager = new DefaultWebSessionManager();
        defaultSessionManager.setSessionValidationSchedulerEnabled(false);
        return defaultSessionManager;
    }

    @Bean
    public DefaultWebSubjectFactory subjectFactory() {
        return new JwtSubjectFactory();
    }

    /**
     * 2、安全管理器
     *
     * @param userRealm 自定义的realm
     * @return 安全管理器
     */
    @Bean(name = "defaultWebSecurityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("realm") UserRealm userRealm,
                                                                  SubjectFactory subjectFactory,
                                                                  SessionManager sessionManager) {
        DefaultWebSecurityManager webSecurityManager = new DefaultWebSecurityManager();
        //向安全管理器注入自定义Realm
        webSecurityManager.setRealm(userRealm);

        //关闭ShiroSession，实现Shiro无状态
        DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
        DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
        defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
        subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
        webSecurityManager.setSubjectDAO(subjectDAO);

        webSecurityManager.setSubjectFactory(subjectFactory);
        webSecurityManager.setSessionManager(sessionManager);
        return webSecurityManager;
    }

    /**
     * 3、shiro的过滤器工厂
     *
     * @param defaultWebSecurityManager 安全管理器
     * @return shiro的过滤器实例
     */
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //设置安全管理器
        shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);

        //shiro自定义过滤器
        Map<String, Filter> filterMap = new LinkedHashMap<>();
        //添加自己的过滤器并且取名为jwt
        filterMap.put("jwt", new JwtFilter());
        shiroFilterFactoryBean.setFilters(filterMap);

        //设置拦截器，使用LinkedHashMap保证Filter的有序性
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        //过滤链定义，从上向下顺序执行，一般将/**放在最为下边
        //请求放行接口,不通过JWTFilter
        filterChainDefinitionMap.put("/user/login", "anon");
        //放行swagger资源
        filterChainDefinitionMap.put("/swagger-ui/**","anon");
        filterChainDefinitionMap.put("/swagger-resources/**","anon");
        filterChainDefinitionMap.put("/v3/**","anon");
        filterChainDefinitionMap.put("/webjars/**","anon");
        //所有请求通过我们自己的JWT Filter
        filterChainDefinitionMap.put("/**", "jwt");

        //修改调整后的登录请求
        shiroFilterFactoryBean.setLoginUrl("/user/toLogin");
        //设置未授权提示请求
        shiroFilterFactoryBean.setUnauthorizedUrl("/user/noAuth");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);

        return shiroFilterFactoryBean;
    }

    /**
     * 开启Shiro的注解，
     * (如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,
     * 并在必要时进行安全逻辑验证 * 配置以下两个bean(DefaultAdvisorAutoProxyCreator(可选)
     * 和AuthorizationAttributeSourceAdvisor)即可实现此功能
     */
    // @Bean
    // public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
    //     DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
    //     //强制使用cglib，防止重复代理和可能引起代理出错的问题
    //     advisorAutoProxyCreator.setProxyTargetClass(true);
    //     return advisorAutoProxyCreator;
    // }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        // 这里需要注入 SecurityManger 安全管理器
        advisor.setSecurityManager(securityManager);
        return advisor;
    }

}